// package: learn-go
// filename: bot5
// author: Administrator@gmail.com
// time: 2023/8/24 18:34
package main

import (
	"context"
	"fmt"
	"time"
)

// Task 表示一个任务
type Task struct {
	Name      string
	Priority  int
	Timeout   time.Duration
	Func      func(ctx context.Context) error
	Retries   int
	OnFail    func() // 任务失败回调
	OnSuccess func() // 任务成功回调
}

// TaskManager 表示一个任务机器人
type TaskManager struct {
	// 任务队列
	queue chan Task
	// 任务执行器
	executor chan Task
	// 任务超时时间
	timeout time.Duration
	// 任务失败重试次数
	maxRetries int
	// 任务失败重试间隔
	retryInterval time.Duration
}

// NewTaskManager 创建一个新的任务机器人
func NewTaskManager(timeout time.Duration, maxRetries int, retryInterval time.Duration) *TaskManager {
	return &TaskManager{
		queue:         make(chan Task, 1000),
		executor:      make(chan Task, 1000),
		timeout:       timeout,
		maxRetries:    maxRetries,
		retryInterval: retryInterval,
	}
}

// Run 启动任务机器人
func (t *TaskManager) Run() {
	go t.worker()
}

// AddTask 添加一个任务
func (t *TaskManager) AddTask(task Task) {
	task.Retries = 0
	t.queue <- task
	t.executor <- task
}

// worker 任务执行器
func (t *TaskManager) worker() {
	for task := range t.executor {
		// 执行任务
		err := task.Func(context.Background())
		if err != nil {
			// 任务失败
			fmt.Println("任务失败：", err)
			if task.Retries < t.maxRetries {
				// 重试任务
				task.Retries++
				t.queue <- task
			} else {
				// 任务失败回调
				if task.OnFail != nil {
					task.OnFail()
				}
			}
		} else {
			// 任务成功
			fmt.Println("任务成功：", task.Name)
			if task.OnSuccess != nil {
				task.OnSuccess()
			}
		}
	}
}

// main 函数
func main() {
	// 创建任务机器人
	tm := NewTaskManager(10*time.Second, 3, 1*time.Second)
	// 启动任务机器人
	tm.Run()

	// 添加任务
	tm.AddTask(Task{
		Name:     "任务1",
		Priority: 1,
		Timeout:  5 * time.Second,
		Func: func(ctx context.Context) error {
			time.Sleep(10 * time.Second)
			fmt.Println("任务1 doing")
			return nil
		},
		OnFail: func() {
			fmt.Println("任务失败")
		},
		OnSuccess: func() {
			fmt.Println("任务成功")
		},
	})
	tm.AddTask(Task{
		Name:     "任务2",
		Priority: 2,
		Timeout:  10 * time.Second,
		Func: func(ctx context.Context) error {
			time.Sleep(20 * time.Second)
			fmt.Println("任务2 doing")
			return nil
		},
		OnFail: func() {
			fmt.Println("任务失败")
		},
		OnSuccess: func() {
			fmt.Println("任务成功")
		},
	})

	// 等待任务完成
	time.Sleep(30 * time.Second)
}
